/*
 *  contact.cpp
 *  EPPI-0.0
 *
 *  Created by Juan Carlos Garcia Orden on 17/03/11
 *
 */

#include "contact.h"

Contact::Contact(ifstream &in, string cname, MecSystem *pSys)
:	Joint(in,cname,pSys)
{	
	dim = parentSystem->dim;	/** Must be set always.  dim belongs to the mother class Joint */
	
	int i;
	char keyword[20];
//	string keyword;
	//	string pointName;
	//	vector<string> auxsv;		/** Aux string vector */
//	string auxs;

	while (in >> keyword && strcmp(keyword,"ENDJOINT") ) 
	{
		cout << keyword << endl;
		// keyword has the CSTIFFNESS label
		in >> cstiffness;
		
		in >> keyword;	// CDAMPING label
		cout << keyword << endl;
		in >> cdamping;
		
		in >> keyword;	// CFRICTION label
		cout << keyword << endl;
		in >> cfriction;		
		
		in >> keyword;	// BODY label.   If particle, it must be first
				cout << keyword << endl;
		in >> bodyName1;
		in >> keyword;	// BODY label
				cout << keyword << endl;
		in >> bodyName2;
	}
	cout << keyword << endl;

	cout << "stiffness\t" << cstiffness << endl;
	cout << "damping\t" << cdamping << endl;
	cout << "friction\t" << cfriction << endl;
/*
	while (in >> keyword && keyword.compare("ENDJOINT"))
	{
		if (!keyword.compare("CSTIFFNESS"))
		{
			in >> cstiffness;
			cout << keyword << "\t" << cstiffness << endl;
		}
		
		if (!keyword.compare("CDAMPING"))
		{
			in >> cdamping;
			cout << keyword << "\t" << cdamping << endl;			
		}
		 
		if (!keyword.compare("CFRICTION"))
		{
			in >> cfriction;
			cout << keyword << "\t" << cfriction << endl;
		}
		 
		if (!keyword.compare("BODY1"))
		{
				cout << keyword << endl;
				in >> bodyName1;
		}
		 
		if (!keyword.compare("BODY2"))
		{
			cout << keyword << endl;
			in >> bodyName2;
		}
	}
	cout << keyword << endl;	
*/	
	if(checkForSlash(bodyName1) == false)
		addSystemName(bodyName1,parentSystem->name);
		 
	if(checkForSlash(bodyName2) == false)
		addSystemName(bodyName2,parentSystem->name);
		 
	// It is assumed that the bodies have been already created
	PBody1 = parentSystem->getPTBodyLocal(bodyName1);
	PBody2 = parentSystem->getPTBodyLocal(bodyName2);

	if (!PBody1->type.compare("rigidbody3d4p") || !PBody1->type.compare("ground") )
	{
		PBody1->getPointNames(vNames1);
	}
	else
	{
		//vNames1 = PBody1->vPointNamesSurface;
		vNames1 = PBody1->vPointNamesContact;
		// vPoinNamesContact names do not have the system name
		for (i=0; i<vNames1.size(); ++i)
		{
			if (checkForSlash(vNames1[i])==false) addSystemName(vNames1[i],parentSystem->name);
		}
	}
		
		
	PBody2->getPointNames(vNames2);
	// Merge both vectors in vNames
	//		for (i=0; i<auxsv.size(); ++i)	vNames.push_back(auxsv[i]);
		
	
	// Components pointRSurface have to be created later, because localPoints of the bodies are no available.
	// Components are created in function createContacts, in this same file
	if(parentSystem->getProcNum() == parentSystem->getRankNum())
		cout << "	Joint " << name << " succesfully read \n";
}

// ***
/*
void Contact::setPTPointsComp()
{
	int j, k;
	vector<string> auxs;
	map<string, Point*, less<string> > maux;
	pair<string,Point*> mauxEntry;
	pair<string,int> sharedEntry;
	
//	for(j=0; j<vComponents.size(); j++)		
	for(j=0; j<vConstraints.size(); j++)		
		//Loop on the components
	{
		//auxs = (vComponents[j]->getPointNames());
		auxs = (vConstraints[j]->getPointNames());
		for(k=0; k<auxs.size(); k++)		
			// Loop on the names of the points within each component
		{
			// If the point it is not at the local process ...
			if( (parentSystem->checkIfPointProcess(auxs[k]))==false )
			{
				// ...  create it at root system, copying the original point from the remote process
				parentSystem->createPointAtRoot( parentSystem->getPTPoint(auxs[k]) );
				// ...  and add the name of the shared point at the remote process 
				//				cout << "Nombre del sistema = " << parentSystem->name << endl;
				//				cout << "en el proceso = " << parentSystem->getProcNum() << endl;
				//				cout << "Nombre del punto = " << auxs[k] << endl;
				parentSystem->addRemoteSharedPoint(auxs[k],parentSystem->getProcNum());
			}
			mauxEntry.first = auxs[k];
			mauxEntry.second = (parentSystem->getPTPointLocal(auxs[k]));
			maux.insert(mauxEntry);
		}
		//vComponents[j]->setMPoints(maux);
		vConstraints[j]->setMPoints(maux);
		maux.clear();
	}
}

// ***

void Contact::setPTPointsLoad()
{
	int j, k;
	vector<string> auxs;
	map<string, Point*, less<string> > maux;
	pair<string,Point*> mauxEntry;
	pair<string,int> sharedEntry;
	
	for(j=0; j<vLoads.size(); j++)		
		//Loop on the Loads
	{
		auxs = (vLoads[j]->getPointNames());
		for(k=0; k<auxs.size(); k++)		
			// Loop on the names of the points within each component
		{
			// If the point it is not at the local process ...
			if( (parentSystem->checkIfPointProcess(auxs[k]))==false )
			{
				// ...  create it at root system, copying the original point from the remote process
				parentSystem->createPointAtRoot( parentSystem->getPTPoint(auxs[k]) );
				// ...  and add the name of the shared point at the remote process
				parentSystem->addRemoteSharedPoint(auxs[k],parentSystem->getProcNum());
			}
			mauxEntry.first = auxs[k];
			mauxEntry.second = (parentSystem->getPTPointLocal(auxs[k]));
			maux.insert(mauxEntry);
		}
		vLoads[j]->setMPoints(maux);
		maux.clear();
	}
}
*/
// ***

void Contact::setPTPointsCons()
{
	int j, k;
	vector<string> auxs;
	map<string, Point*, less<string> > maux;
	pair<string,Point*> mauxEntry;
	pair<string,int> sharedEntry;
	
	for(j=0; j<vConstraints.size(); j++)		
		//Loop on the Loads
	{
		auxs = (vConstraints[j]->getPointNames());
		for(k=0; k<auxs.size(); k++)		
			// Loop on the names of the points within each component
		{
			/** If the point it is not at the local process ... */
			if( (parentSystem->checkIfPointProcess(auxs[k]))==false )
			{
				/** ...  create it at root system, copying the original point from the remote process */
				parentSystem->createPointAtRoot( parentSystem->getPTPoint(auxs[k]) );
				/** ...  and add the name of the shared point at the remote process */
				parentSystem->addRemoteSharedPoint(auxs[k],parentSystem->getProcNum());
			}
			mauxEntry.first = auxs[k];
			mauxEntry.second = (parentSystem->getPTPointLocal(auxs[k]));
			maux.insert(mauxEntry);
		}
		vConstraints[j]->setMPoints(maux);
		maux.clear();
	}			
}

// ***

/*
 void Contact::setPTBodies()
 {}
 */
// ***

void Contact::setPPointSurface()
{
	/*
	 // Build the vector of pointers to the surface points
	 vPPointSurface.resize(vPointNamesSurface.size());
	 
	 int i;
	 string auxs;
	 for(i=0;i<vPointNamesSurface.size();i++)
	 {
	 auxs = vPointNamesSurface[i];
	 if(checkForSlash(auxs)==false)	addSystemName(auxs,parentSystem->name);
	 vPPointSurface[i] = parentSystem->getPTPointLocal( auxs );
	 }
	 */
}

// ***

void Contact::writeMSH(ofstream &fGraph)
{}

// ***

void Contact::writeVTU(ofstream &fGraph)
{
	localFGraph << "<?xml version=\"1.0\"?>\n";
	localFGraph << "<VTKFile type=\"UnstructuredGrid\" version=\"0.1\" byte_order=\"LittleEndian\">\n";
	localFGraph << "	<UnstructuredGrid>\n";
	localFGraph << "		<Piece NumberOfPoints=\"" << 0 << "\" NumberOfCells=\"" << 0 << "\">\n";
	localFGraph << "			<Points>\n";
	localFGraph << "				<DataArray type=\"Float64\" NumberOfComponents=\"3\" format=\"ascii\">";
	localFGraph << "\n";
	localFGraph << "				</DataArray>\n";
	localFGraph << "			</Points>\n";
	localFGraph<< "			<Cells>\n";
	localFGraph << "				<DataArray type=\"Int32\" Name=\"connectivity\" format=\"ascii\">";
	
	localFGraph << "\n";
	localFGraph << "					";
	
	localFGraph << "\n";
	localFGraph << "				</DataArray>\n";
	localFGraph << "				<DataArray type=\"Int32\" Name=\"offsets\" format=\"ascii\">";
	localFGraph << "\n";
	localFGraph << "					";
	
	localFGraph << "\n";
	localFGraph << "				</DataArray>\n";
	localFGraph << "				<DataArray type=\"UInt8\" Name=\"types\" format=\"ascii\">";
	localFGraph << "\n";
	localFGraph << "					";
	
	localFGraph << "\n";
	localFGraph << "				</DataArray>\n";
	localFGraph<< "			</Cells>\n";
	
	localFGraph << "		</Piece>\n";
	
	localFGraph << "	</UnstructuredGrid>\n";
	localFGraph << "</VTKFile>\n";		
}

// ***

void Contact::writeOOGL(ofstream &fGraph)
{}

// ***
/*
void Contact::writeFileTemp(const double&, ofstream &)
{}
*/
// ***
/*
void Contact::setIniPosJoint(vector<double>& iniValues)
{}
*/
// ***

void Contact::createContacts()
{
	// Generation of contacts
	// Each contact is defined with a localpoint of body1 and the surface of body2
	// Loop on the local points of body1
	
	int i;
	int j;
	vector<string> vNames;
	vector<double> vContactPoint;
	
	string BType1 = PBody1->type;
	string BType2 = PBody2->type;
	
	vContactPoint.resize(3);
	
	/*
	 if (PBody1->type.compare("rigidbody3d4p") && ( !PBody2->type.compare("rigidbody3d4p") || !PBody2->type.compare("ground") ) )
	 {
	 for (i=0; i<vNames1.size(); ++i)
	 {
	 vNames.push_back(vNames1[i]);
	 for (j=0; j<vNames2.size(); ++j)	vNames.push_back(vNames2[j]);
	 // First name in vNames must be particle point name
	 //
	 // Uncomment the desired element
	 vComponents.push_back(new NodeRSurfaceDD(vNames,dim,this));	// Discrete derivative
	 //vComponents.push_back(new NodeRSurfaceBeta(vNames,dim,this));	// With beta
	 //vComponents.push_back(new NodeRSurfaceBetaR(vNames,dim,this));	// With beta - Roberto formulation
	 
	 vNames.clear();
	 }
	 }
	 */
	if(!BType1.compare("rigidbody3d4p") and
	   (!BType2.compare("rigidbody3d4p") or !BType2.compare("ground")))
	{
		// Body1 = RigidBody
		// Body2 = RigidBody or Ground
		
		// Merge vNames1 and vNames2
		for (i = 0; i < vNames2.size(); ++i)
			vNames1.push_back(vNames2[i]);
		
		for (i = 0; i < PBody1->surface->vContactPoints.size(); ++i)
		{
			/*
			vComponents.push_back(new PointRSurface(vNames1,
													dim,
													PBody1->surface->vContactPoints[i],
													this));
			*/
			vConstraints.push_back(new PointRSurface(vNames1,
													dim, 
													PBody1->surface->vContactPoints[i], 
													this));			
		}
	}
	
	if(BType1.compare("rigidbody3d4p") and
	   (!BType2.compare("rigidbody3d4p") or !BType2.compare("ground")))
	{
		// Body1 = FlexiBody
		// Body2 = RigidBody or Ground
		
		for (i = 0; i < vNames1.size(); ++i)
		{
			// First name in vNames must be particle point name
			vNames.push_back(vNames1[i]);
			for (j=0; j<vNames2.size(); ++j)
				vNames.push_back(vNames2[j]);
			/*

			vComponents.push_back(new PointRSurface(vNames,
													dim,
													vContactPoint,
													this));	
			*/
			vConstraints.push_back(new PointRSurface(vNames,
													dim,
													vContactPoint,
													this));				
			vNames.clear();
		}
	}	
}
